package com.zhiyou100.demo.util;

import com.zhiyou100.demo.model.SysPermission;
import com.zhiyou100.demo.model.SysRole;
import com.zhiyou100.demo.model.UserInfo;
import com.zhiyou100.demo.service.UserInfoServiceImpl;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;

/**
 * @Author: suzhinan
 * @CreateTime: 2019-11-18 22:00
 * @Description:
 */

public class MyShiroRealm extends AuthorizingRealm {

    @Resource
    private UserInfoServiceImpl userInfoService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("进入授权方法");
        System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        UserInfo userInfo  = (UserInfo)principals.getPrimaryPrincipal();// shiro的subject.get(),得到当前主体
        for(SysRole role:userInfo.getRoleList()){// 通过当前用户拿到关联的角色
            authorizationInfo.addRole(role.getRole());// 向授权对象中添加角色
            System.out.println("该用户拥有的角色:"+role.getRole());
            for(SysPermission p:role.getPermissions()){ // 通过角色拿到关联的权限
                System.out.println("该用户拥有的权限:"+p.getPermission());
                authorizationInfo.addStringPermission(p.getPermission());// 向当前授权对象添加权限
            }
        }
        return authorizationInfo; // 返回授权对象
    }

    /*主要是用来进行身份认证的，也就是说验证用户输入的账号和密码是否正确。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        System.out.println("进入认证方法");
        System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
        //获取用户的输入的账号.
        String username = (String)token.getPrincipal();
        System.out.println(token.getCredentials());
        //通过username从数据库中查找 User对象，如果找到，没找到.
        //实际项目中，这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法
        UserInfo userInfo = userInfoService.findByUsername(username);
        System.out.println("----->>userInfo="+userInfo);
        if(userInfo == null){
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userInfo, //用户
                userInfo.getPassword(), //密码
                ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        System.out.println("认证中打印pwd:"+userInfo.getPassword());
        System.out.println("认证中打印凭证:"+userInfo.getCredentialsSalt());//username+salt
        System.out.println("认证中打印realm name:"+getName());
        return authenticationInfo;
    }
   /* 当两个用户的密码相同时，单纯使用不加盐的MD5加密方式，会发现数据库中存在相同结构的密码，
    这样也是不安全的。我们希望即便是两个人的原始密码一样，加密后的结果也不一样。
    如何做到呢？其实就好像炒菜一样，两道一样的鱼香肉丝，加的盐不一样，炒出来的味道就不一样。
    MD5加密也是一样，需要进行盐值加密。*/

}
